/*
 * run_config_plot.cpp
 *
 *  Created on: 20.07.2013
 *      Author: SpirTanol
 */

#include "ui/run_config_plot.h"
#include "device/protection.h"
#include "app_config.h"

// Qwt
#include <qwt_legend.h>
#include <qwt_scale_widget.h>
#include <qwt_scale_engine.h>
#include <qwt_scale_div.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_layout.h>
#include <qwt_plot_picker.h>

// Qt
#include <QFontMetrics>
#include <QThread>
#include <QMetaType>
#include <QDebug>
//======================================================================================
const double RunConfigPlot::scCurrent[] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.12, 1.26, 1.41, 1.58, 1.77, 1.98, 2.22, 2.49, 2.79, 3.13, 3.51, 3.94, 4.41, 4.95, 5.54, 6.22, 6.97, 7.81, 8.75, 9.81, 11.0 };
const double RunConfigPlot::scCurNomTime[2] = { 0.001, 100000.0 };
//======================================================================================
RunConfigPlot::RunConfigPlot() :  QwtPlot(0)
{
	init();
}

RunConfigPlot::RunConfigPlot(const RunConfigPlot* plot)
{
	init();

	oNomCurrent = plot->oNomCurrent;
	oCurrentDuration = plot->oCurrentDuration;
	oCurrent = plot->oCurrent;
	oCurNom[0] = plot->oCurNom[0];
	oCurNom[1] = plot->oCurNom[1];
	oCurScale = plot->oCurScale;

	oRunConfigCurve->setData(oCurrent, oCurrentDuration);
	oProtection->copyConfig(plot->oProtection);

	replot();
}

RunConfigPlot::~RunConfigPlot()
{
	if (oThread)
	{
		oThread->terminate();
		oThread->wait();
	}
	delete oProtection;
}
//======================================================================================
void RunConfigPlot::init()
{
	qRegisterMetaType<QVector<double> >("QVector<double>");

	oThread = 0;

	plotLayout()->setAlignCanvasToScales(false);

	QwtLegend *legend = new QwtLegend;
	legend->setItemMode(QwtLegend::ReadOnlyItem);
	insertLegend(legend, QwtPlot::RightLegend);

	setAutoReplot(false);

	setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignHCenter | Qt::AlignBottom);

	QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom);
	const int fmh = QFontMetrics(scaleWidget->font()).height();
	scaleWidget->setMinBorderDist(0, fmh / 2);
	QwtText text;
	text.setFont(QFont("Arial", 10, 8, false));
	text.setText(trUtf8("Время (с)"));
	setAxisTitle(QwtPlot::yLeft, text);
	text.setText(trUtf8("Ток (А)"));
	setAxisTitle(QwtPlot::xBottom, text);
	setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine());
	setAxisScale(QwtPlot::xBottom, 0.1, 15);
	setAxisScale(QwtPlot::yLeft, 0.001, 600);
	setCanvasBackground(QColor(240, 241, 239));

	oRunConfigCurve = new QwtPlotCurve(trUtf8("Пусковая характеристика"));
	oRunConfigCurve->attach(this);

	QColor c = QColor(Qt::green);
	oRunConfigCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
	oRunConfigCurve->setPen(c);
	c.setAlpha(75);
	oRunConfigCurve->setBrush(c);
	oRunConfigCurve->setBaseline(0.001);
	oRunConfigCurve->show();

	oProtectCurve = new QwtPlotCurve(trUtf8("Характеристика защит"));
	oProtectCurve->setPen(QColor("#0000FF"));
	oProtectCurve->attach(this);
	oProtectCurve->show();

	oNomCurrentCurve = new QwtPlotCurve(trUtf8("Номинальный ток"));
	oNomCurrentCurve->setPen(QColor("#FF0000"));
	oNomCurrentCurve->attach(this);
	oNomCurrentCurve->show();

	QwtPlotGrid *grid = new QwtPlotGrid;
	grid->enableY(true);
	grid->enableYMin(true);
	grid->enableX(true);
	grid->enableXMin(false);
	grid->setMajPen(QPen(Qt::blue, 0, Qt::DotLine));
	grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
	grid->attach(this);

	//Подсказка над курсором
	new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
	QwtPicker::PointSelection,
	QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOn, canvas());

	oProtection = new Protection();

	setLogBottomScale(AppConfig::i()->scaleType() == ST_LOGO);
}
//======================================================================================
void RunConfigPlot::updateRunConfigData(const QVector<double> &currentDuration, double nomCurrent)
{
	oNomCurrent = nomCurrent;

	oCurrent.clear();
	oCurrentDuration = currentDuration;
	for(int i = 0;i < 32;i++)
		oCurrent.push_back(scCurrent[i] * nomCurrent);

	for(int i = 0;i < oCurrentDuration.count();i++)
	{
		if(oCurrentDuration[i] == 0.0)
			oCurrentDuration[i] = 0.001;
	}
	oRunConfigCurve->setData(oCurrent, oCurrentDuration);
	replot();
}
//======================================================================================
void RunConfigPlot::setLogBottomScale(bool enable)
{
	if(enable)
	{
		setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine());
		if(oProtectCurve->dataSize() > 0)
			setAxisScale(QwtPlot::xBottom, 0.08, oProtectCurve->data().x(oProtectCurve->dataSize() - 1));
	}
	else
	{
		setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine());
		if(oProtectCurve->dataSize() > 0)
			setAxisScale(QwtPlot::xBottom, 0, oProtectCurve->data().x(oProtectCurve->dataSize() - 1));
	}
	replot();
}
//======================================================================================
void RunConfigPlot::updateConfigs(const ConfigPacket *config)
{
	oProtection->setConfig(config);
}
//======================================================================================
void Worker::buildGraph()
{
	QVector<double> time;
	QVector<double> current;
	double nomCur = double(oPlot->oProtection->curNom() / oPlot->oCurScale);

	// Генирируем точки
	for (int i = 1; i < 60; ++i)
	{
		current.push_back(nomCur * (i * 0.01));
		time.push_back((oPlot->oProtection->get_trip_time(u32(i * 10)) * 0.000001));
	}

	for (int i = 60; i < 700; i += 20)
	{
		current.push_back(nomCur * (i * 0.01));
		time.push_back((oPlot->oProtection->get_trip_time(u32(i * 10)) * 0.000001));
	}

	for (int i = 700; i < 1500; i += 50)
	{
		current.push_back(nomCur * (i * 0.01));
		time.push_back((oPlot->oProtection->get_trip_time(u32(i * 10)) * 0.000001));
	}

	// Строим график
	oPlot->oCurNom[0] = nomCur;
	oPlot->oCurNom[1] = nomCur;

	//oPlot->oProtectCurve->setData(current, time);
	//oPlot->oNomCurrentCurve->setRawData(oPlot->oCurNom, RunConfigPlot::scCurNomTime, 2);

	if (thread() == oPlot->thread())
		oPlot->onBuildProtectionGraphFinished(current, time);
	else
		QMetaObject::invokeMethod(oPlot, "onBuildProtectionGraphFinished", Qt::QueuedConnection,
				Q_ARG(QVector<double>, current),
				Q_ARG(QVector<double>, time));
}

void RunConfigPlot::buildProtectionGraph(bool inThread)
{
	if (oThread) return;

	Worker *worker = new Worker(this);
	if (inThread)
	{
		oThread = new QThread();
		worker->moveToThread(oThread);
		oThread->start();
		QMetaObject::invokeMethod(worker, "buildGraph", Qt::QueuedConnection);
		return;
	}
	worker->buildGraph();
	delete worker;
}

void RunConfigPlot::onBuildProtectionGraphFinished(QVector<double> current, QVector<double> time)
{
	oThread = 0;

	if(dynamic_cast<QwtLinearScaleEngine *>(axisScaleEngine(QwtPlot::xBottom)))
		setAxisScale(QwtPlot::xBottom, 0, current.back());
	else
		setAxisScale(QwtPlot::xBottom, current.first(), current.back());

	oProtectCurve->setData(current, time);
	oNomCurrentCurve->setRawData(oCurNom, RunConfigPlot::scCurNomTime, 2);

	replot();
	emit buildProtectionGraphFinished();
}
